package org.abox.tools.ant.taskdefs.mks.common;

import org.abox.tools.ant.taskdefs.mks.common.Connection.Type;
import org.abox.tools.ant.taskdefs.mks.util.EqualsBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

import com.mks.api.CmdRunner;
import com.mks.api.Command;
import com.mks.api.response.APIException;
import com.mks.api.response.Response;

/**
 *
 * @author oleksandr_korobka
 *
 */
public abstract class BaseTask extends Task {

	private static final Log LOG = LogFactory.getLog(BaseTask.class);

	private Connection connection;

	// Class variables used to create an API Session
	private String hostName;
	private int port;
	private String userName;
	private String password;
	private boolean secure;
	// The type of connection to MKS Sever: Local or Remote.
	private final String type = Type.LOCAL.name();

	public void setConnectionRefId(String connectionRef) {
		Object ds = getProject().getReference(connectionRef);
		if (!(ds instanceof Connection)) {
			throw new BuildException("Unexpected reference id: "
					+ connectionRef);
		}
		setConnection((Connection) ds);
	}

	protected void setConnection(Connection connection) {
		if (this.connection != null) {
			try {
				this.connection.createSession();
			} catch (APIException e) {
				LOG.error("Unable to close session: ", e);
			}
		}

		this.connection = connection;
	}

	protected Connection getConnection() {

		if (isNativeConnectionRequired()) {
			setConnection(createNativeConnection());
		}

		return connection;
	}

	protected Connection createNativeConnection() {
		if (this.connection == null) {
			return Connection.newConnection(
					getHostName(), getPort(), getUserName(), getPassword(), isSecure());
		}

		Connection c = Connection.copyConnection(this.connection);
		if (getHostName() != null) {
			c.setHostName(getHostName());
		}
		if (getPort() != 0) {
			c.setPort(getPort());
		}
		if (getUserName() != null) {
			c.setUserName(getUserName());
		}
		if (getPassword() != null) {
			c.setPassword(getPassword());
		}
		if (isSecure()) {
			c.setSecure(isSecure());
		}

		return c;
	}

	protected boolean isNativeConnectionRequired() {
		return connection == null
				|| !(new EqualsBuilder()
						.appendInsensitive(connection.getHostName(),
								getHostName())
						.append(connection.getPort(), getPort())
						.appendInsensitive(connection.getUserName(),
								getUserName())
						.append(connection.getPassword(), getPassword())
						.append(connection.isSecure(), isSecure()).isEquals());
	}

	/**
	 * This function executes a generic API/CLI Command
	 *
	 * @param cmd
	 *            MKS API Command Object representing a CLI command
	 * @return MKS API Response Object
	 * @throws APIException
	 */
	protected Response runCommand(Command cmd) throws APIException {
		Connection connection = getConnection();

		CmdRunner cmdRunner = connection.getSession().createCmdRunner();
		cmdRunner.setDefaultHostname(connection.getHostName());
		cmdRunner.setDefaultPort(connection.getPort());
		cmdRunner.setDefaultUsername(connection.getUserName());
		cmdRunner.setDefaultPassword(connection.getPassword());
		Response res = cmdRunner.execute(cmd);
		LOG.debug(res.getCommandString() + " returned exit code "
				+ res.getExitCode());
		cmdRunner.release();
		return res;
	}

	@Override
	public String toString() {
		return "BaseTask [connection=" + connection + ", hostName=" + hostName
				+ ", port=" + port + ", userName=" + userName + ", type="
				+ type + "]";
	}

	public void setHostName(String hostName) {
		this.hostName = hostName;
	}

	public String getHostName() {
		return hostName;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getPort() {
		return port;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getUserName() {
		return userName;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}

	public String getType() {
		return type;
	}

	public void setSecure(boolean secure) {
		this.secure = secure;
	}

	public boolean isSecure() {
		return secure;
	}

}
